package ru.papergames.model.proxies
{
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	import mx.collections.ArrayCollection;
	import ru.papergames.controller.notifications.CoreNotifications;
	import ru.papergames.model.binsocket.data.ExtByteArray;
	import ru.papergames.model.binsocket.events.SocketConnectionEvent;
	import ru.papergames.model.binsocket.MessagingPacketManager;
	import ru.papergames.model.binsocket.packets.request.*;
	import ru.papergames.model.binsocket.packets.response.*;
	import ru.papergames.model.binsocket.packets.SocketRequest;
	import ru.papergames.model.binsocket.packets.SocketResponse;
	import ru.papergames.model.proxies.BaseSocketProxy;
	import ru.papergames.model.proxies.SettingsProxy;
	import ru.papergames.model.vo.ChatChanellVO;
	import ru.papergames.model.vo.MessagingConnectVO;
	import ru.papergames.model.vo.PlayerVO;
	import ru.papergames.model.vo.PopupMessageVO;
	import ru.papergames.utils.constants.ConfigKeys;
	
	
	
	public class MessagingSocketProxy extends BaseSocketProxy
	{
		public static const NAME:String = 'MessagingSocketProxy';
		
		public static const CONNECTION_SUCCESS:String = 'MessagingSocketProxy.CONNECTION_SUCCESS';
		public static const CONNECTION_CLOSED:String = 'MessagingSocketProxy.CONNECTION_CLOSED';
		public static const CONNECTION_ERROR:String = 'MessagingSocketProxy.CONNECTION_ERROR';
		
		public static const DATA_SENDED:String = 'MessagingSocketProxy.DATA_SENDED';
		public static const DATA_RECIEVED:String = 'MessagingSocketProxy.DATA_RECIEVED';
				
		public var lastSentPacket:SocketRequest;
		
		public var loggedIn:Boolean = false;
		
		private var players:Dictionary = new Dictionary();		
		private var myPlayerId:Number;
		
		private var channels:ArrayCollection = new ArrayCollection();
		
		private var _messagingPingTimer:Timer;
		
		private var nickMAP:Object = { };
		
		private var accessProxy:MsgServerAccessProxy;
		
		private var poolProxy:PlayersPoolProxy;
		
		
		public function MessagingSocketProxy()
		{
			super(NAME, new ExtByteArray());
		}
		
		override public function onRegister():void {
			super.onRegister();
			
			accessProxy = new MsgServerAccessProxy(this.settingsProxy.getProperty(ConfigKeys.GET_ACCESS_TO_BATTLE_SERVER));
			facade.registerProxy(accessProxy);
			
			poolProxy = new PlayersPoolProxy(this.settingsProxy.getProperty(ConfigKeys.ADD_PLAYER_IN_BASE_FIGHTERS_POOL_URL));
			facade.registerProxy(poolProxy);
			
			channels.addItem(new ChatChanellVO(ChatChanellVO.CHANNEL_MAIN));
			
			_messagingPingTimer = new Timer(settingsProxy.getNumberProperty(ConfigKeys.MESSAGING_PING_INTERLEAVE, 10000), 0);
			
			addListeners();
		}
		
		override public function onRemove():void {
			
			facade.removeProxy(MsgServerAccessProxy.NAME);			
			accessProxy = null;			
			
			facade.removeProxy(PlayersPoolProxy.NAME);			
			poolProxy = null;	
			
			players = null;			
			
			super.onRemove();
			
			removeListeners();
			
			recievedBytes.cleanup();
			this.sendData(null);
			lastSentPacket = null;
			nickMAP = null;
			
			mainChannel.members.list.removeAll();
			channels.list.removeAll();
			
			_messagingPingTimer.stop();
			
			_messagingPingTimer = null;
		}
		
		protected function get settingsProxy():SettingsProxy {
			return this.getProxy(SettingsProxy.NAME) as SettingsProxy;
		}
				
		private function addListeners():void {
			_messagingPingTimer.addEventListener(TimerEvent.TIMER, pingMessagingServer);
		}
		
		private function removeListeners():void {
			_messagingPingTimer.removeEventListener(TimerEvent.TIMER, pingMessagingServer);
		}
		
		private function pingMessagingServer(evt:TimerEvent):void {
			send( new PingRequest() );
		}
		
		
		public function getAccessInfo():void {
			accessProxy.call(MsgServerAccessProxy.GET_DATA);
		}
		
		public function joinToPlayersPool():void {
			poolProxy.call(PlayersPoolProxy.GET_DATA);
		}
		
		
		override public function disconnect():void {
			super.disconnect();
			
			accessProxy.connVO.playerID = null;
			accessProxy.connVO.server = null;
			accessProxy.connVO.port = null;			
			accessProxy.connVO.secretKey = 0;
		}
		
		
		
		public function addPlayer(p:PlayerVO):void {
			
			if ( getPlayer(p.playerId) ) return;
			
			players[p.playerId] = p;			
			if (p.isMine) myPlayerId = p.playerId;
		}
		
		public function addPlayers(list:Array):void {
			for each (var p:PlayerVO in list) {
				addPlayer(p);
			}
		}
		
		public function removePlayer(playerId:Number):void {
			delete players[playerId];
		}
		
		public function getMyPlayer():PlayerVO {
			return myPlayerId ? players[myPlayerId] as PlayerVO : null;
		}
		
		public function getPlayer(playerId:Number):PlayerVO {
			return players[playerId] as PlayerVO;
		}
		
		public function getPlayers():Array {
			var rez:Array = [];
			
			for each (var p:PlayerVO in players) {
				rez.push(p);
			}
			
			return rez;
		}
		
		public function setPlayerInTurn(playerId:Number):void {
			
			for each (var p:PlayerVO in players) {
				p.inTurn = p.playerId == playerId;
			}
			
		}
		
		
		
		public function get mainChannel():ChatChanellVO {
			return getChannel(ChatChanellVO.CHANNEL_MAIN);
		}
		
		public function get battleChannel():ChatChanellVO {
			return getChannel(ChatChanellVO.CHANNEL_BATTLE);
		}
		
		public function getChannel(name:String):ChatChanellVO {
			for each (var ch:ChatChanellVO in channels) {
				if (ch.name == name) return ch;
			}
			
			return null;
		}
		
		public function get members():ArrayCollection {
			return mainChannel.members;
		}
		
				
		public function get recievedBytes():ExtByteArray {
			return this.data as ExtByteArray;
		}
		
		override public function tryConnect(connVO:MessagingConnectVO):void {
			connectionVO = connVO;
			
			if (!sdManager.connected) sdManager.initialize(connVO.server, Number(connVO.port));
		}
		
		
		public function sendMessage(msg:String, recipientId:uint = 0, forTeam:Boolean = false, global:Boolean = false):void {			
			
		}
		
		public function send(data:SocketRequest):void	
		{				
			//check if connection is active
			if (!sdManager.connected) {
				
				facade.sendNotification(CoreNotifications.SYS_ERROR, new PopupMessageVO('Соединение не активно!', 'Ошибка'));
				
				return;
			}
			
			lastSentPacket = data;
			sendData(data.getBytes());
			logger.debug('sendData: ' + data.toString());
			facade.sendNotification(DATA_SENDED, data);
			facade.sendNotification(data.getNotification(), data);
		}
		
		override protected function onConnect(evt:SocketConnectionEvent):void {
			super.onConnect(evt);
			
			//try login
			send(new AuthLoginRequest(Number(connectionVO.playerID), connectionVO.secretKey));
		}
		
		override protected function onDisconnect(evt:SocketConnectionEvent):void {
			super.onDisconnect(evt);
			
			loggedIn = false;
			
			_messagingPingTimer.stop();
		}
		
		override protected function onData(data:ExtByteArray):void {
			super.onData(data);
			
			this.data = data;
			recievedBytes.recieved = true;
			
			var response:SocketResponse = MessagingPacketManager.getResult(recievedBytes);
			
			if (response) {
				logger.debug('onData: ' + response.toString());
				facade.sendNotification(DATA_RECIEVED, response);
				handleResponse(response);				
			} else {
				logger.error('Unknown packet format: ' + recievedBytes.toString());
			}
		}
		
		protected function handleResponse(response:SocketResponse):void {
			
			
			switch ( response.getName() ) {
				case AuthorizationPassedResponse.NOTIFICATION:
					loggedIn = true;
					_messagingPingTimer.start();
					break;
			}
			
			facade.sendNotification(response.getNotification(), response);
		}
		
	}
}